/**
* AutoSWF - Cody Cushing. March 26, 2009
* Copyright (c) 2009 Cody Cushing
* No use restrictions. Maintain this notice in all versions. 
**/

package com.autoswf.taskrunner
{
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	
	/**
	 * Uses a TaskRunner to execute tasks, maintains a hash of requests to prevent id collisions 
	 * on requests with the same key.
	 */	
	public class TaskModel extends EventDispatcher
	{
		protected var taskRunner:TaskRunner;
		protected var requestHash:Dictionary;


		/**
		 * Constructor.
		 */		
		public function TaskModel(taskRunner:TaskRunner)
		{
			this.taskRunner = taskRunner;
			this.taskRunner.addEventListener(TaskEvent.TASK_COMPLETE, taskRunner_completeHandler);
			this.taskRunner.addEventListener(TaskEvent.TASK_FAILURE, taskRunner_failureHandler);
			
			requestHash = new Dictionary();
		}
		
		
		public function result(id:String):*
		{
			return taskRunner.result(id);
		}


		/**
		 * Add a request for processing, chain id collisions into subscriber list.
		 */
		public function addTask(request:IRequest):void
		{
			if(requestHash[request.id]) // if this task key already exist, add the task to the chain
			{
				(requestHash[request.id] as Array).push(request);
			}
			else // task doesnt exist, start a new chain for the id and add the task
			{
				requestHash[request.id] = [request];
				taskRunner.addTask(request);
			}
		}
		
		
		/**
		 * Fired when the task completes, invokes the completeHandler callback on each request 
		 * passing the completed task to the handler. 
		 */
		protected function taskRunner_completeHandler(event:TaskEvent):void
		{
			var requestList:Array = requestHash[event.id];
			var result:* = taskRunner.result(event.id);

			while(requestList.length)  // there is a request(s) waiting for a result
			{
				var request:IRequest = requestList.shift(); // process requests in order
				request.result = result; // store the result reference
				
				if(request.completeHandler != null) // invoke the complete handler if there is one
				{
					request.completeHandler(request); // passing the original request
				}
			}
			delete requestHash[event.id];
			
			dispatchEvent(event);
		}
		
		
		/**
		 * Invokes the errorHandler on each request with matching id.
		 */		
		protected function taskRunner_failureHandler(event:TaskEvent):void
		{
			var requestList:Array = requestHash[event.id];

			while(requestList.length)
			{
				var request:IRequest = requestList.pop();
				if(request.errorHandler != null)
				{
					request.errorHandler(request);
				}
			}
			delete requestHash[event.id];
			
			dispatchEvent(event);
		}

	}
}
